
import type { Ref, UnwrapRef } from "vue"
import { ref, watch, onUnmounted } from "vue"

interface IDebounceFn<T> {
    (...args: T[]): void | Promise<void>
}

/**
 * 防抖工具函数（注：此时它还不是个hook，因为hook既要存储一些复用的逻辑，也要涉及变量的封装）
 * @param fn   传入的函数
 * @param wait 延迟时间
 */
export function debounceUtil<T>(fn: IDebounceFn<T>, wait: number) {
    let timer: number | null = null
    return function f(this: void, ...args: T[]) {
        if (timer) {
            clearTimeout(timer)
        }
        // setTimeout是Node.js下的接口定义文件，定义的是Timeout类型，而这里timer是number类型
        // 所以使用window.setTieout()方否，返回的就是Number类型
        // 亦或者可以定义timer为：let timer: number | NodeJS.Timeout = null
        timer = window.setTimeout(() => {
            fn.call(this, ...args)
        }, wait)
    }
}

/**
 * 防抖钩子函数
 * @param value 传进来的要监听的变量
 * @param wait 延迟时间
 * return 
 */
export function useDebounce<T>(value: Ref<T>, wait: number) {
    const debounceValue = ref(value.value)
    let timer: number | null = null

    // unwatch 记录当前watch的值，用于组件销毁前使用
    const unwatch = watch(value, (nv) => {
        if (timer) {
            clearTimeout(timer)
        }
        timer = window.setTimeout(() => {
            debounceValue.value = nv as UnwrapRef<T>
        }, wait)
    })

    onUnmounted(() => {
        unwatch()
    })

    return debounceValue
}

